home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
raytrace
/
rayshade
/
graphtal.lzh
/
Graphtal.Amiga
/
LSystem.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-11-17
|
7KB
|
299 lines
/*
* LSystem.C - methods for classes ProductionSlot, Table and LSystem.
*
* Copyright (C) 1992, Christoph Streit (streit@iam.unibe.ch)
* University of Berne, Switzerland
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
*/
#include "LSystem.h"
#include "Options.h"
implementList(TableList, TablePtr);
implementList(DerivationList, DerivationItemPtr);
//___________________________________________________________ Table Hashing
unsigned int modHash(const char* aString, long arg) {
return (hash(aString, arg) % HASH_ARRAY_SIZE);
}
static inline unsigned int rehash(int place) {
return (place + 17) % HASH_ARRAY_SIZE;
}
//___________________________________________________________ Production
ProductionSlot::ProductionSlot(Production* p)
: name(p->name())
{
argCount = p->argCount();
productions = new ProductionList(1);
productions->append(p);
}
ProductionSlot::~ProductionSlot()
{
delete productions;
}
void ProductionSlot::append(Production* p)
{
productions->append(p);
}
int ProductionSlot::match(Production* p) const
{
return (name == p->name()) && (argCount == p->argCount());
}
int ProductionSlot::match(Module* m) const
{
return (name == m->name()) && (argCount == m->argCount());
}
//___________________________________________________________ Table
/*
* Takes a list of productions and stores them in a hashed array
* to achieve fast access.
*/
Table::Table(const Name& n, ProductionList* plist)
: _name(n), productions(plist)
{
register long i;
int hashvalue;
/*
* Initialize the array.
*/
for (i=0; i<HASH_ARRAY_SIZE; i++)
pslots[i] = NULL;
for (i=0; i<plist->count(); i++) {
hashvalue = plist->item(i)->hashValue();
/*
* Try to find a slot to store the production; a infinite loop can
* occur, if we need more than HASH_ARRAY_SIZE ProductionSlots,
* which will rarely happen!
*/
while(1) {
/*
* No ProductionSlot yet -> instantiate a new one.
*/
if (pslots[hashvalue] == NULL) {
pslots[hashvalue] = new ProductionSlot(plist->item(i));
break;
}
/*
* ProductionSlot is present, but is it the right on for the
* production.
*/
else if (pslots[hashvalue]->match(plist->item(i))) {
pslots[hashvalue]->append(plist->item(i));
break;
}
/*
* Not lucky yet, try another place.
*/
else
hashvalue = rehash(hashvalue);
}
}
}
Table::~Table()
{
long i;
for (i=0; i<productions->count(); i++)
delete productions->item(i);
delete productions;
for (i=0; i<HASH_ARRAY_SIZE; i++)
if (pslots[i])
delete pslots[i];
}
/*
* Apply steps-times the productions of the table to the given list of
* modules.
*/
ModuleList* Table::execute(ModuleList* m, int steps)
{
result = new ModuleList(1000);
for (register long i=0; i<m->count(); i++)
rexecute(m->item(i), steps);
delete m;
return result;
}
/*
* Recursively apply the productions of the table to the given module.
*/
void Table::rexecute(Module* m, int steps)
{
ModuleList* r;
if (steps != 0) // -1 = INFINITY, STOP when 0
if (r = apply(m)) {
for (register long i=0; i<r->count(); i++)
rexecute(r->item(i), steps-1);
delete m;
delete r;
}
else
result->append(m);
else
result->append(m);
}
/*
* Look for a matching production and evaluate the replacement for
* the module m.
*/
ModuleList* Table::apply(Module* m)
{
int hashvalue = m->hashValue();
while(1) {
/*
* Is there a production which matches the module name and the
* number number of arguments of the module m.
*/
if (pslots[hashvalue])
if (pslots[hashvalue]->match(m)) {
/*
* Yes: bind the actual parameters of the module to the formal
* ones of the productions stored in the ProductionSlot.
*/
m->bind();
break;
}
else
hashvalue = rehash(hashvalue);
else
return NULL; // no production could be applied
}
/*
* Clone the successor of the first production in the ProductionSlot
* which condition evaluates to TRUE.
*/
ProductionList* pl = pslots[hashvalue]->productions;
for (register long i=0; i<pl->count(); i++)
if (pl->item(i)->evalCondition())
return pl->item(i)->cloneSuccessor();
/*
* No production could be applied.
*/
return NULL;
}
ostream& operator<<(ostream& os, const Table& t)
{
os << "table " << t._name << '\n';
for (long i=0; i<t.productions->count(); i++)
os << " " << *t.productions->item(i);
return os;
}
//___________________________________________________________ LSystem
ostream& operator<<(ostream& os, const DerivationItem& d)
{
os << d.table->name() << '(';
if (d.steps < 0)
os << "infinity";
else
os << d.steps;
os << ')';
return os;
}
LSystem::LSystem(const Name& n, TableList* t, ProdModuleList* a,
DerivationList* d)
: name(n), tables(t), axiom(a), derivation(d)
{}
LSystem::~LSystem()
{
long i;
for (i=0; i<tables->count(); i++)
delete tables->item(i);
delete tables;
for (i=0; i<axiom->count(); i++)
delete axiom->item(i);
delete axiom;
for (i=0; i<derivation->count(); i++)
delete derivation->item(i);
delete derivation;
}
ModuleList* LSystem::execute()
{
ModuleList* result;
DerivationItem* d;
register long i;
/*
* Replace the ProdModuleList by a ModuleList -> 0. iteration step.
*/
result = new ModuleList(axiom->count());
for (i=0; i<axiom->count(); i++)
result->append(new Module(axiom->item(i)));
if (!theOptions.quiet) cerr << "\nExecution:\n";
for (i=0; i<derivation->count(); i++) {
d = derivation->item(i);
if (!theOptions.quiet) cerr << "\tTable " << *d << '\n';
result = d->table->execute(result, d->steps);
}
if (theOptions.verbose)
cerr << "\n\n#Modules: " << result->count() << "\n\n";
return result;
}
ostream& operator<<(ostream& os, const LSystem& lsys)
{
os << "lsystem " << lsys.name << "\n\n";
for (long i=0; i<lsys.tables->count(); i++)
os << *lsys.tables->item(i) << '\n';
os << "Axiom ";
for (i=0; i<lsys.axiom->count(); i++)
os << *lsys.axiom->item(i) << ' ';
os << '\n';
os << "Derivation ";
for (i=0; i<lsys.derivation->count(); i++)
os << *lsys.derivation->item(i) << ' ';
os << '\n';
return os;
}